package com.jymj.controller;

import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.jymj.common.config.SmsConfig;
import com.jymj.common.shiro.JwtTokenUtil;
import com.jymj.entity.SysMenuEntity;
import com.jymj.entity.SysUserEntity;
import com.jymj.service.SysMenuService;
import com.jymj.service.SysUserService;
import com.jymj.utils.*;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * 登录相关
 *
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2016年11月10日 下午1:15:31
 */
@Controller
public class SysLoginController {

    private final Logger LOGGER = LoggerFactory.getLogger(SysLoginController.class);
    @Autowired
    private Producer producer;
    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private SysUserService sysUserService;
    private static final String KEY = "MOBILE_NUMBER::";

    @RequestMapping("captcha.jpg")
    public void captcha(HttpServletResponse response) throws ServletException, IOException {
        //设置响应头允许ajax跨域访问*
        response.setHeader("Access-Control-Allow-Origin", "*");
        //星号表示所有的异域请求都可以接受，
        response.setHeader("Access-Control-Allow-Methods", "GET,POST");
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        //生成文字验证码
        String text = producer.createText();
        //生成图片验证码
        BufferedImage image = producer.createImage(text);
        //保存到shiro session
        //ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
    }

    /**
     * 登录
     *
     * @param username
     * @param password
     * @param response
     * @return
     * @throws IOException
     */
    @ResponseBody
    @RequestMapping(value = "/sys/login", method = RequestMethod.POST)
    public R prolegin(String username, String password, HttpServletResponse response) throws IOException {
        try {
            Subject subject = ShiroUtils.getSubject();
            //sha256加密0
            password = new Sha256Hash(password).toHex();
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            subject.login(token);
            String strToken = JwtTokenUtil.generateToken(token.getUsername());
            SysUserEntity user = ShiroUtils.getUserEntity();
            //user = sysUserService.queryObjectType(user.getUserId());
            //RedisUtil.del(username);
            return R.ok().put("token", strToken).put("user", user);
        } catch (UnknownAccountException | IncorrectCredentialsException | LockedAccountException e) {
            LOGGER.error(e.getMessage(), e);
            return R.error(e.getMessage());
        } catch (AuthenticationException e) {
            LOGGER.error(e.getMessage(), e);
            return R.error("账户验证失败");
        }
    }

    /**
     * 登录
     *
     * @param username
     * @param password
     * @param captcha
     * @return
     * @throws IOException
     */
    @ResponseBody
    @RequestMapping(value = "/sys/backstage", method = RequestMethod.POST)
    public R login(String username, String password, String captcha) throws IOException {
        try {
            Subject subject = ShiroUtils.getSubject();
            //sha256加密
            password = new Sha256Hash(password).toHex();
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            subject.login(token);
        } catch (UnknownAccountException | IncorrectCredentialsException | LockedAccountException e) {
            LOGGER.error(e.getMessage(), e);
            return R.error(e.getMessage());
        } catch (AuthenticationException e) {
            LOGGER.error(e.getMessage(), e);
            return R.error("账户验证失败");
        }

        return R.ok();
    }

    /**
     * 登录
     *
     * @param username
     * @param deviceCode
     * @param password
     * @param response
     * @return
     * @throws IOException
     */
    @ResponseBody
    @RequestMapping(value = "/sys/applogin")
    public Map applogin(String username, String password, String deviceCode, HttpServletResponse response) throws IOException {
        //设置响应头允许ajax跨域访问*
        response.setHeader("Access-Control-Allow-Origin", "*");
        //星号表示所有的异域请求都可以接受，
        response.setHeader("Access-Control-Allow-Methods", "GET,POST");
        Map<String, Object> map = new HashMap<>();
        Subject subject = ShiroUtils.getSubject();
        //sha256加密0
        password = new Sha256Hash(password).toHex();
        try {
            if (deviceCode == null || deviceCode.equals("")) {
                map.put("code", 501);
                map.put("msg", "获取机器码失败！");
                return map;
            }
            SysUserEntity user = sysUserService.queryByUserName(username);
            if (user == null) {
                map.put("code", 502);
                map.put("msg", "用户名或密码错误！");
                return map;
            } else {
                if (!password.equals(user.getPassword())) {
                    map.put("code", 503);
                    map.put("msg", "用户名或密码错误！");
                    return map;
                }
            }
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            subject.login(token);
            if (user.getDeviceCode() != null && !user.getDeviceCode().equals("")) {
                if (!deviceCode.equals(user.getDeviceCode())) {
                    map.put("code", 504);
                    map.put("msg", "机器码错误！");
                    return map;
                }
            } else {
                user.setDeviceCode(deviceCode);
                sysUserService.updateDeviceCode(user);
            }
            //123456  sha256加密后 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
            if (password.equals("8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92")) {
                map.put("code", 505);
                map.put("msg", "密码太过简单！");
                return map;
            }
            SysUserEntity user1 = ShiroUtils.getUserEntity();
            user1 = sysUserService.queryObjectType(user1.getUserId());
            //只有超级管理员，才能查看所有管理员列表
            List<SysMenuEntity> menuList = sysMenuService.queryAppUserList(user1.getUserId());
            user1.setMenuList(menuList);
            user1.setXzqs(user.getXzqs() == null ? null : user.getXzqs());
            user1.setCode(user.getCode() == null ? null : user.getCode());
            user1.setXzqmc(user.getXzqmc() == null ? null : user.getXzqmc());
            map.put("user", user1);
            map.put("code", 0);
            map.put("msg", null);
            String strToken = JwtTokenUtil.generateToken(token.getUsername());
            //RedisUtil.del(username);
            map.put("token", strToken);
            return map;
        } catch (UnknownAccountException | IncorrectCredentialsException | LockedAccountException e) {
            LOGGER.error(e.getMessage(), e);
            return R.error(e.getMessage());
        } catch (AuthenticationException e) {
            LOGGER.error(e.getMessage(), e);
            return R.error("账户验证失败");
        }
    }

    @ResponseBody
    @PostMapping("/sys/authBymobile")
    public R authBymobile(String mobile, String code, Long userId) {
        if (mobile.isEmpty() || !NumberUtil.isPhone(mobile)) {
            throw new RRException("手机号码格式不正确");
        }
        //验证code
        RedisUtils redisUtils = new RedisUtils();
        if (!redisUtils.exist(KEY+mobile)) {
            throw new RRException("验证码过期请重新获取");
        }
        String tempCode = redisUtils.get(KEY+mobile);
        if (!tempCode.equals(code)) {
            throw new RRException("验证码错误,请输入正确的验证码");
        }
        try {
            //查询用户
            List<SysUserEntity> sysUserEntities = sysUserService.getUserByMobile(mobile);
            if (sysUserEntities.size() > 1 && userId == null) {
                return R.ok("请选择需要登陆的账号").put("data", sysUserEntities);
            }
            SysUserEntity sysUserEntity = new SysUserEntity();
            if (sysUserEntities.size() == 0) throw new RRException("用户不存在");
            if (sysUserEntities.size() > 1 && userId != null) {
                for (SysUserEntity userEntity : sysUserEntities) {
                    if (userEntity.getUserId().equals(userId))
                        sysUserEntity = userEntity;
                }
            } else {
                sysUserEntity = sysUserEntities.get(0);
            }
            Subject subject = ShiroUtils.getSubject();
            UsernamePasswordToken token =
                    new UsernamePasswordToken(sysUserEntity.getUsername(), sysUserEntity.getPassword(), true);
            String strToken = JwtTokenUtil.generateToken(sysUserEntity.getUsername());
            subject.login(token);
            SysUserEntity user = ShiroUtils.getUserEntity();
            if (!sysUserEntity.getMobile().equals(mobile)) {
                return R.ok("请重新设置手机号码保证号码中无中文").put("token", strToken).put("user", user);
            }
            return R.ok().put("token", strToken).put("user", user);
        } catch (UnknownAccountException uaex) {
            return R.error(uaex.getMessage());
        } catch (IncorrectCredentialsException icex) {
            return R.error(icex.getMessage());
        } catch (LockedAccountException laex) {
            return R.error(laex.getMessage());
        }
    }

    @Autowired
    private SmsConfig smsConfig;

    @ResponseBody
    @PostMapping("/sys/getCode")
    public R getCode(String mobile, HttpSession session) {
        if (mobile.isEmpty() || !NumberUtil.isPhone(mobile)) {
            throw new RRException("手机号码格式不正确");
        }
        Integer seconds = 604800;
        String vcode = "";
        RedisUtils redisUtils = new RedisUtils();
        for (int i = 0; i < 6; i++) {
            vcode = vcode + (int) (Math.random() * 9);
        }
        String key = KEY+mobile;
        redisUtils.setex(key, seconds, vcode);
        smsConfig.init(2);
        String[] phone = {"+86" + mobile};
        String[] params = {vcode, Integer.toString(300 / 60)};
        SmsUtils.sendSmsInfo(phone, params);
        //发送短信 获取验证码
        return R.ok("发送成功");
    }

    /**
     * 退出
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "logout", method = RequestMethod.GET)
    public String logout() {
        ShiroUtils.logout();
        return "redirect:login.html";
    }

    /**
     * 退出
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "webLogout", method = RequestMethod.POST)
    public R webLogout() {
        ShiroUtils.logout();
        return R.ok();
    }

    @Autowired
    private DefaultKaptcha defaultKaptcha;

    @GetMapping("/sys/getKaptcha")
    @ResponseBody
    public void defaultKaptcha(HttpSession session, HttpServletResponse httpServletResponse) throws Exception {
        byte[] captchaOutputStream = null;
        ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
        try {
            //生产验证码字符串并保存到session中
            String verifyCode = defaultKaptcha.createText();
            session.setAttribute("verifyCode", verifyCode);
            httpServletResponse.setHeader("verifyCode", verifyCode);
            BufferedImage challenge = defaultKaptcha.createImage(verifyCode);
            ImageIO.write(challenge, "jpg", imgOutputStream);
        } catch (IllegalArgumentException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        captchaOutputStream = imgOutputStream.toByteArray();
        httpServletResponse.setHeader("Cache-Control", "no-store");
        httpServletResponse.setHeader("Pragma", "no-cache");
        httpServletResponse.setDateHeader("Expires", 0);
        httpServletResponse.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
        responseOutputStream.write(captchaOutputStream);
        responseOutputStream.flush();
        responseOutputStream.close();
    }


}
